#include "device.h"
#include "finger.h"
#include "osal.h"
#include "uart_finger.h"
#include "debug_config.h"

/* 调试打印接口 */
#define FINGER_LOG(format, ...) TASK_LOG(C_GREEN format C_NONE, ##__VA_ARGS__)

#define UART_VHW_FINGER vUART_10
#define IRQ_VHW_FINGER vPIN_I5
#define POWER_VHW_FINGER vPIN_C29

/* 指纹检测事件 */
#define EVENT_FINGER_DETECT (0X00000001) // 指纹检测事件
#define EVENT_INIT_FINGER (0X00000002)
#define EVENT_UART_PROTOCOL (0X00000004)
#define EVENT_SHAKE_PROTOCOL (0X00000008) // 握手事件
#define EVENT_GETIMAGE_PROTOCOL (0X00000010) // 采图事件
//#define EVENT_FINGER_VERSION (0X00000020) // 读取版本号事件
#define EVENT_FINGER_LED_OFF (0X00000040) // 关闭所有LED事件


void Finger_Processor(void);
void Finger_EndStep(void);
void Finger_Cancel(void);

/* 指纹当前状态*/
typedef enum
{
	FINGER_IDLE, //空闲状态
	FINGER_BUSY, //忙碌状态
} Finger_WorkStatus_enum_t;

/* 手指当前状态*/
typedef enum
{
	FINGER_UP,   //抬起状态
	FINGER_DOWN, //按下状态
} Finger_Status_enum_t;


/* FINGER组件的NV大小 */
#define FINGER_NV_SIZE (40) // 目前用于存版本号（18byte）-旧的指纹模块有35byte，先创40个
/* 特征缓存最小个数 */
#define FINGER_CHAR_NUM (5) // 最少采集到5次算成功


/* 指纹启动标志 */
static uint8_t start_flag = 0;
/* 指纹初始化标志 */
static uint8_t init_flag = 0;
/* 指纹存储编号 */
static uint8_t temp_save_num = 0;
/* 指纹当前状态 */
static Finger_WorkStatus_enum_t cur_status = FINGER_IDLE;
/* 手指当前状态 */
static Finger_Status_enum_t finger_status = FINGER_UP;
/* 特征缓存ID */
static uint8_t bufferID = 1;
/* 添加指纹状态 */
static uint8_t add_state = 0;



/* 定义发送缓存 */
static uint8_t uart_tx_buffer[MAX_PACKAGE_LEN] = {0};
static uint16_t tx_ctrl_flg = 0;
void (*Finger_send_timeout_cb)(void) = NULL;
/* 指纹运行状态 */
Finger_Status_Data_stu_t finger_status_data;
/* 休眠标志  1:休眠前已发送休眠指令给指纹模组  0:休眠前需要发送休眠指令给指纹模组*/
static uint8_t fpt_sleep_flag = 0;
/* 生成特征回调后,发送验证指纹的指令:1  验证指纹执行回调完成或者超时: 0 */
static uint8_t fpt_verify_flag = 0;
/* 通信状态  1:可以和指纹模组通信 0:不能和指纹模组通信*/
static uint8_t connect_state = 0;

uint8_t get_fpt_sleep_flag(void)
{
    uint8_t ret = 0;

    ret = fpt_sleep_flag;
    return ret;
}

void set_fpt_sleep_flag(uint8_t flag)
{
    fpt_sleep_flag = flag;
}
/**
 * @brief  打印HEX数据，最多只能打印32字节
 * @note
 *
 * @param  pData：数据指针
 * @param  len：数据长度
 */
static void Finger_PrintfHexData(char *Msg, uint8_t *pData, uint16_t len)
{
    char *str_buffer = OSAL_Malloc(len * 3 + 1);
    if (str_buffer != NULL)
    {
        memset(str_buffer, 0, len * 3 + 1);
        FINGER_LOG("%s:%d(Bytes)\r\n", Msg, len);
        if (str_buffer != NULL)
        {
            for (int i = 0; i < len; i++)
            {
                sprintf(&str_buffer[i * 3], "%02X ", pData[i]);
            }
            FINGER_LOG("%s\r\n\r\n", str_buffer);
        }
    }
    if (str_buffer)
        OSAL_Free(str_buffer);
}

/**
 * @brief  计算数据和
 * @note
 *
 * @param  pbuf：数据指针
 * @param  len：数据长度
 */

uint16_t Finger_CalcCheckSum(uint8_t *pbuf, uint16_t len)
{
    uint16_t i;
    uint16_t sum = 0;

    for (i = 0; i < len; i++)
    {
        sum += *(pbuf + i);
    }
    return sum;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/***************************************串口处理********************************************/
// 超时处理
void Finger_wait_acktimeout(void)
{
    FINGER_LOG("Finger_wait_acktimeout\r\n");
    Finger_DetectNoFinger_cb(); 
    //Finger_Cancel();// 
    fpt_verify_flag = 0;
}

/**
 * @brief  Uart任务 协议层初始化
 *
 * @note
 */
static void Finger_ProtocolInit(void)
{
    CmdPacketTxInfo.status = TX_STA_IDLE;
    CmdPacketTxInfo.cnt = 0;
    CmdPacketRxInfo.status = RX_STA_IDLE;
    CmdPacketRxInfo.rx_msg = NULL;
    memset(CmdPacketRxInfo.protocolBuf, 0, sizeof(CmdPacketRxInfo.protocolBuf));
    CmdPacketRxInfo.protocolCount = 0;
    Finger_send_timeout_cb = Finger_wait_acktimeout; //--- 
}

/**
 * @brief  获取发送缓存区的状态
 * @note
 *
 * @return 缓存区为空返回0
 */
static uint8_t Finger_GetTxBufferStatus(void)
{
    return tx_ctrl_flg;
}

/**
 * @brief  处理发送缓存
 * @note   将发送缓存区的数据，通过串口发出，并处理Int控制逻辑
 *
 */
static void Finger_ProcessTxBuffer(void)
{
    uint8_t *pSendBuf = uart_tx_buffer;
    if (tx_ctrl_flg > 0)
    {
        /* 调用硬件层write接口，发出数据 */
        #if 0
        Finger_PrintfHexData("Uart send packet", pSendBuf, tx_ctrl_flg);
        #endif 
        Device_Write(UART_VHW_FINGER, pSendBuf, tx_ctrl_flg, 0);
        tx_ctrl_flg = 0;
    }
}

/**
 * @brief  从底层环形缓存获取一包数据并解析
 *
 * @note   底层驱动收到数据，会暂存在环形缓存区
 *
 * @return 返回解析后的数据包地址，解析失败返回NULL
 */
static uint8_t *Finger_GetOnePacket(void)
{
    static uint8_t getPacketTimeoutCnt = 0;
    uint8_t tmpData = 0;
    uint16_t sum;

    if (OSAL_RingBufferRead(CmdPacketRxInfo.rbHandle, &tmpData) == 0)
    {
        /* 连续3次没有读取到数据（30ms） */
        if (++getPacketTimeoutCnt >= 3)
        {
            getPacketTimeoutCnt = 0;
            CmdPacketRxInfo.protocolCount = 0; // 清0解析计数
        }
        return NULL;
    }
    getPacketTimeoutCnt = 0;

    uint8_t *pCnt = &(CmdPacketRxInfo.protocolCount);    // 解析计数
    uint8_t *protocolBuff = CmdPacketRxInfo.protocolBuf; // 解析缓存
    do
    {
        if (*pCnt <= 1)
        {
            if (tmpData == 0xEF)
            {
                protocolBuff[0] = tmpData;
                *pCnt = 1;
            }
            else if (*pCnt == 1 && tmpData == 0x01)
            {
                protocolBuff[1] = tmpData;
                *pCnt = 2;
            }
            else if (tmpData == 0x55) // 指纹上电初始化成功后，会返回0x55,之后MCU和指纹模组才可进行指令交互
            {
                FINGER_LOG("ringbuff: %02X\r\n", tmpData);
                connect_state = 1;
                //FINGER_LOG("connect_state 001:%x", connect_state);
            }
            else 
            {
                FINGER_LOG("tmpData:%x", tmpData);
                if(connect_state == 1)
                {
                     Finger_Processor(); //00A
                }    
            }
        }
        else if (*pCnt > 1) // 包头通过后才开始解析数据
        {
            protocolBuff[*pCnt] = tmpData;
            *pCnt = *pCnt + 1;
            if (*pCnt > 8)
            {
                CmdPacket_stu_t *pPacketHead = (CmdPacket_stu_t *)protocolBuff;

                uint16_t packetLen;
                packetLen = OSAL_SWAP16(pPacketHead->head.len) + 9;
                if (*pCnt >= MAX_PACKAGE_LEN || packetLen == *pCnt)
                {
                    if (packetLen == *pCnt)
                    {
                        sum = protocolBuff[packetLen - 2] * 256 + protocolBuff[packetLen - 1];
                        if (sum == Finger_CalcCheckSum(&protocolBuff[6], OSAL_SWAP16(pPacketHead->head.len) + 1))
                        {
                            // FINGER_TASK_LOG_HEX("Uart Rx", protocolBuff, packetLen);
                            *pCnt = 0;
                            return protocolBuff; // 接收完成
                        }
                        else
                        {
                            FINGER_TASK_LOG_HEX("Uart Rx CRC ERR", protocolBuff, packetLen);
                        }
                    }
                    *pCnt = 0;
                    return NULL;
                }
            }
        }
    } while (OSAL_RingBufferRead(CmdPacketRxInfo.rbHandle, &tmpData));
    return NULL;
}

/**
 * @brief  处理应答包0x07
 * @note
 *
 * @param  pData：数据包地址
 */
void Finger_ProcessRxConfrimPacket(uint8_t *pData)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)pData;
    #if 0
    FINGER_LOG("confrim_code:%2X", pPackeData->confrim_code);
    #endif 
    CmdPacketRxInfo.timeStamp = OSAL_GetTickCount();


    if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK)
    {
        if (CmdPacketTxInfo.data.cb != NULL)
        {
            CmdPacketTxInfo.data.cb(pData);
            CmdPacketTxInfo.data.cb = NULL;
        }

        CmdPacketTxInfo.status = TX_STA_IDLE;
    }
}

/**
 * @brief  处理数据包0x02
 * @note
 *
 * @param  pData：数据包地址
 */
void Finger_ProcessRxDataPacket(uint8_t *pData)
{
    // TODO 暂时没用到
    DataPacket_stu_t *pPackeData = (DataPacket_stu_t *)pData;
}

/**
 * @brief  解析接收的数据包
 * @note
 *
 * @param  pData：数据包地址
 */
static void Finger_ParseRxPacket(uint8_t *pData)
{
    ProtocolDataHead_stu_t *pPacketHead = (ProtocolDataHead_stu_t *)pData;

    if (pData == NULL)
    {
        return;
    }

    if (pPacketHead->pack_flg == FINGER_PACK_ACK)
    {
        /* 处理接收的确认包 */
        Finger_ProcessRxConfrimPacket(pData);
    }
    else if (pPacketHead->pack_flg == FINGER_PACK_DATA)
    {
        /* 处理接收的数据包 */
        // Finger_ProcessRxDataPacket(pData);
    }
    else if (pPacketHead->pack_flg == FINGER_PACK_CMD)
    {
        /* 处理接收的命令包 */
    }
    else
    {
        /* 处理接收数据结束包 */
        // Finger_ProcessRxDataPacket(pData);
    }
}

/**
 * @brief  重发命令包，并处理超时逻辑
 *
 * @note   MCU发出命令包后，超时没有收到确认包，就重发
 */
static void Finger_CmdTimeoutProess(void)
{
    uint8_t send_timeout_msg = 0;
    uint32_t currentTime = OSAL_GetTickCount();
    //static uint8_t count = 0;
    //count++;

    // if (count >= 100)
    // {
    //     FINGER_LOG(">>>>>>CmdTimeoutProess ");
    //     count = 0;

    //     FINGER_LOG("CmdPacketTxInfo.status:%d", CmdPacketTxInfo.status);
    //     FINGER_LOG("CmdPacketRxInfo.timeStamp:%d", CmdPacketRxInfo.timeStamp);
    //     FINGER_LOG("CmdPacketTxInfo.timeStamp:%d", CmdPacketTxInfo.timeStamp);
    //     FINGER_LOG("Rx-Tx:%d, CmdPacketTxInfo.data.acktimeout:%d", CmdPacketRxInfo.timeStamp - CmdPacketTxInfo.timeStamp, CmdPacketTxInfo.data.acktimeout);
    // }

    if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK) // 等待应答包
    {
        CmdPacketRxInfo.timeStamp = OSAL_GetTickCount();//更新RX时间戳，解决没有收到完整数据包，没有把状态设置为IDLE,从而没发采图指令的问题
        if (CmdPacketRxInfo.timeStamp > CmdPacketTxInfo.timeStamp)
        {
            if ((CmdPacketRxInfo.timeStamp - CmdPacketTxInfo.timeStamp) > CmdPacketTxInfo.data.acktimeout)
            {
                FINGER_LOG("cur time : %X\r\n", CmdPacketRxInfo.timeStamp);
                FINGER_LOG("send time : %X\r\n", CmdPacketTxInfo.timeStamp);
                FINGER_LOG("out time : %X\r\n", CmdPacketTxInfo.data.acktimeout);

                // 打印超时指令
                FINGER_LOG("wait ack timeout [0x%x]\r\n", CmdPacketTxInfo.data.buffer[9]);
                send_timeout_msg = 1;
                CmdPacketTxInfo.status = TX_STA_IDLE;
            }
        }
    }

    /* exec timeout callback */
    if (send_timeout_msg)
    {
        if (Finger_send_timeout_cb != NULL)
        {
            Finger_send_timeout_cb();//
        }
        FINGER_LOG("\r\n send msg timeout ... \r\n");
    }
}

/**
 * @brief  Uart任务 通信协议处理
 *
 * @note   该函数会每间隔10ms执行一次
 */
static void Finger_ProtocolPro(void)
{
    if (Finger_GetTxBufferStatus() != 0)
    {
        Finger_ProcessTxBuffer(); // 处理发送缓存中的数据
    }
    else
    {
        Finger_ParseRxPacket(Finger_GetOnePacket()); // 解析数据
        Finger_CmdTimeoutProess();                   // 重发命令包
    }
}

/**
 * @brief  判断协议层是否为空闲状态
 * @note
 *
 * @return 空闲：返回SUCCESS， 正忙：返回ERROR
 */
static ErrorStatus Finger_IsProtocolIdle(void)
{
    /* 当前没有发出命令、发送缓存为空、接收的命令也处理完成了，才能发出新命令 */
    if (CmdPacketTxInfo.status == TX_STA_IDLE && Finger_GetTxBufferStatus() == 0 && CmdPacketRxInfo.status == RX_STA_IDLE)
    {
        return SUCCESS;
    }
    return ERROR;
}

/**
 * @brief  加载待发送的数据
 * @note   将要发出的数据，填入发送缓存区
 *
 * @param  pData：数据指针
 * @param  len：数据长度
 * @return 成功返回SUCCESS，失败返回ERROR
 */
static ErrorStatus Finger_LoadingDataToBeSent(uint8_t *pData, uint16_t len)
{
    uint8_t *pSendBuf = uart_tx_buffer;
    #if 0
    FINGER_LOG("uart_tx_cmd:%02X\r\n", pData[9]);
    #endif
    if (tx_ctrl_flg == 0)
    {
        tx_ctrl_flg = len;
        memcpy(pSendBuf, pData, len);
        return SUCCESS;
    }
    FINGER_LOG("Loading Tx data failed\r\n");
    return ERROR;
}

// 处理TX队列
static void Finger_ProcessTxQueue(void)
{
    uart_txcmd_packet_stu_t txcmd_packet = {0};
    //  if (connect_state == 0)  //00B TODO: 要确保，指纹上电，并在正常通信状态才能发送数据
    //  {
    //      return;
    //  }

    if (Finger_IsProtocolIdle() != SUCCESS)
    {
        return;
    }
    if (OSAL_RingBufferRead(CmdPacketTxInfo.tbHandle, &txcmd_packet) != SUCCESS)
    {
        return;
    }
    CmdPacketTxInfo.data = txcmd_packet;
    CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();
    CmdPacketTxInfo.cnt = 1;
    CmdPacketTxInfo.status = TX_STA_WAIT_ACK;
    Finger_LoadingDataToBeSent(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);
}

/**
 * @brief  串口接收回调
 *
 * @return
 */
static void Finger_Receivecb(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    /* 收到的数据写入缓存 */
    int i;
    uint8_t *tmp = (uint8_t *)data;
    for (i = 0; i < len; i++)
    {
        OSAL_RingBufferWrite(CmdPacketRxInfo.rbHandle, tmp + i);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/***************************************命令包数据处理********************************************/

/**
 * @brief  组命令包并发送给指纹模组
 * @note 命令包包头和校验和在函数里配置好的
 * @param cmd 命令
 * @param pbuf 内容
 *
 **/
void Finger_send_cmd_pack(uint8_t cmd, uint8_t *pbuf, uint16_t len) //TODO: 要确保，指纹上电，并在正常通信状态才能发送数据
{
    uint8_t buf[50];
    uint16_t i;
    uint16_t sum;
    buf[0] = (PROTOCOL_PACKET_STX >> 8) & 0XFF; // 0xEF01
    buf[1] = (PROTOCOL_PACKET_STX)&0XFF;
    buf[2] = (PROTOCOL_IC_ADDR >> 24) & 0XFF;
    buf[3] = (PROTOCOL_IC_ADDR >> 16) & 0XFF;
    buf[4] = (PROTOCOL_IC_ADDR >> 8) & 0XFF;
    buf[5] = (PROTOCOL_IC_ADDR)&0XFF; // 0xFFFFFFFF

    buf[6] = 0x01; // CMD标识

    buf[7] = (len + 3) / 256;
    buf[8] = (len + 3) % 256;

    buf[9] = cmd;

    if (pbuf != NULL)
    {
        memcpy(&buf[10], pbuf, len);
    }

    sum = Finger_CalcCheckSum(&buf[6], len + 4);
    buf[10 + len] = sum / 256;
    buf[11 + len] = sum % 256;

    uart_txcmd_packet_stu_t *send_packer = NULL;
    send_packer = (uart_txcmd_packet_stu_t *)OSAL_Malloc(sizeof(uart_txcmd_packet_stu_t));

    if (send_packer != NULL)
    {
        memcpy(send_packer->buffer, buf, len + 12);
        send_packer->len = len + 12;

        //if (start_flag == 0)
       // {
            if(buf[9] == PS_GETIMAGE || buf[9] == PS_GetENROLLIMAGE)
            {
                send_packer->acktimeout = 300;
            }
            else
            {
                send_packer->acktimeout = 2000; 
            }
            
        //}
        // else
        // {
        //     send_packer->acktimeout = 500;
        // }

        send_packer->cb = NULL;
        for (i = 0; i < ACK_HANDLER_LENGH; i++)
        {
            if (Ack_HandleFun[i].cmd == cmd)
            {
                send_packer->cb = Ack_HandleFun[i].callback;
                break;
            }
        }

        if (CmdPacketTxInfo.tbHandle != NULL)
        {
            #if 0
            FINGER_LOG("Ringbuffer write\r\n");
            #endif
            CmdPacketTxInfo.cmd = cmd;
            OSAL_RingBufferWrite(CmdPacketTxInfo.tbHandle, send_packer);
        }
        OSAL_Free(send_packer);
    }
}

/**
 * @brief  验证指纹
 * @note
 * @return
 */
void Finger_Search(void)
{
    FINGER_LOG("Finger_Search\r\n");
    uint8_t data_buf[5];
    data_buf[0] = 1; // 缓冲区
    data_buf[1] = 0; // 起始页
    data_buf[2] = 0; 
    data_buf[3] = 0; // 页数
    data_buf[4] = KOS_PARAM_USERS_QTY_FINGER; //50
    Finger_send_cmd_pack(PS_SEARCH, data_buf, 5);
}

/**
 * @brief  删除指纹
 * @note
 * @return
 */
void Finger_DeleteChar(uint8_t startNum, uint8_t Num)
{
    uint8_t data_buf[4];
    data_buf[0] = startNum / 256;
    data_buf[1] = startNum % 256;
    data_buf[2] = Num / 256;
    data_buf[3] = Num % 256;
    Finger_send_cmd_pack(PS_DELETCHAR, data_buf, 4);
}

/**
 * @brief  存储模板
 * @note
 * @return
 */
void Finger_StoreChar()
{
    uint8_t data_buf[3];
    data_buf[0] = 1;
    data_buf[1] = temp_save_num / 256;
    data_buf[2] = temp_save_num % 256;
    Finger_send_cmd_pack(PS_STORECHAR, data_buf, 3);
}

/**
 * @brief  读取版本号
 * @note
 * @return
 */
void Finger_ReadVersion()
{
    uint8_t data = 0x10;
    Finger_send_cmd_pack(PS_READ_VERSION, &data, 1);
}

/**
 * @brief  发送取消指令
 * @note
 * @return
 */
void Finger_Cancel(void)
{
    CmdPacketTxInfo.status = TX_STA_IDLE;

    uint8_t uart_on = (uint8_t)Device_Read(POWER_VHW_FINGER, NULL, 0, 0);
    FINGER_LOG("uart_on:%d\r\n", uart_on);
    if (uart_on == 1)
    {
        Finger_send_cmd_pack(PS_CANCEL, NULL, 0);
    }
}


/**
 * @brief  LED控制
 * @note
 * @return
 */
void Finger_LedSet(Finger_Led_Control_stu_t *Finger_LedControl)
{    
    // Finger_send_cmd_pack(PS_CONTROL_LED, Finger_LedControl, sizeof(Finger_Led_Control_stu_t));
    // if( Finger_LedControl->mode == FINGER_BREATHING_LED__MODE ||  Finger_LedControl->mode == FINGER_FLASHING_LED_MODE)
    // {
    //     // 防止唤醒握手成功 LED关闭打断控制逻辑
    //     OSAL_EventDelete(COMP_FINGER, EVENT_FINGER_LED_OFF);
        
    //     OSAL_EventSingleCreate(COMP_FINGER, EVENT_FINGER_LED_OFF, 500, EVT_PRIORITY_MEDIUM);

    // }
}

/**
 * @brief  LED控制
 * @note
 * @return
 */
void Finger_AllLedOff(void)
{    
    // 关闭所有led
    FINGER_LOG("Finger_AllLedOff\r\n");
    Finger_Led_Control_stu_t ledControl = {0};
    ledControl.mode = FINGER_LED_OFF_MODE;
    ledControl.startColor = FINGER_LED_ALL_OFF;
    ledControl.endColor = FINGER_LED_ALL_OFF;
    ledControl.times = 0;
    Finger_LedSet(&ledControl);
}


/***************************************回调函数处理********************************************/

/**
 * @brief  获取图像回调
 * @note
 * @return
 */
void Finger_GetImage_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    FingerMsg_t fingerMsg;
    #if 0
    FINGER_LOG("Finger_GetImage_cb\r\n");
    #endif
    if (pPackeData->confrim_code == ACK_SUCCESS) // 成功
    {
        // 生成特征
        if (finger_status == FINGER_UP)
        {
            if (finger_status_data.mode == FINGER_WORK_MODE_ADD)
            {
                add_state = 1;
            }
            FINGER_LOG("GetImage success, bufferID:%d\r\n", bufferID);
            fingerMsg.action = FINGER_ACTION_GET_IMAGE_OK;
            fingerMsg.fingerNumber = temp_save_num;
            if (finger_status_data.mode != FINGER_WORK_MODE_DISABLE)
            {
                OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));
           
                Finger_send_cmd_pack(PS_GENCHAR, &bufferID, 1);
            }
        }
        else
        {
            // 按下一直没松手
            if (finger_status_data.mode == FINGER_WORK_MODE_ADD)
            {
            }
            else
            {
                Finger_EndStep();
            }
        }
        finger_status = FINGER_DOWN;
    }
    else
    {
        if (pPackeData->confrim_code == ACK_NO_FINGER)
        {
            finger_status = FINGER_UP;
        }
        else
        {
            FINGER_LOG("FINGER_ACTION_GET_IMAGE_ERR confrim_code %d\r\n",pPackeData->confrim_code);  //获取图像失败
            fingerMsg.action = FINGER_ACTION_GET_IMAGE_ERR;
            fingerMsg.fingerNumber = temp_save_num;
            OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));
        }

        if (finger_status_data.mode == FINGER_WORK_MODE_ADD)
        {
            add_state = 0;
            FINGER_LOG("wait next\r\n");
        }
        else
        {
                // FINGER_LOG("fpt sleep\r\n");
                // Finger_send_cmd_pack(PS_SLEEP, NULL, 0);
                Finger_DetectNoFinger_cb();
        }
    }
}

/**
 * @brief  生成特征回调
 * @note
 * @return
 */
void Finger_GenChar_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    FingerMsg_t fingerMsg;

    if (finger_status_data.mode == FINGER_WORK_MODE_ADD)
    {
        if (finger_status_data.enroll_num < (FINGER_ADD_TIMES - 1))
        {
            finger_status_data.enroll_num++;
            if (pPackeData->confrim_code == ACK_SUCCESS)
            {
                bufferID++;
                fingerMsg.action = FINGER_ACTION_ENTER_AGAIN;
                fingerMsg.fingerNumber = temp_save_num;
                fingerMsg.finger_add_cnt = finger_status_data.enroll_num;
                OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));
            }
            FINGER_LOG("times:%d, success:%d\r\n", finger_status_data.enroll_num, bufferID);
            FINGER_LOG("finger_add_cnt:%d\r\n", fingerMsg.finger_add_cnt);
        }
        else if (finger_status_data.enroll_num >= (FINGER_ADD_TIMES - 1))
        {
            OSAL_EventDelete(COMP_FINGER, EVENT_GETIMAGE_PROTOCOL); // 删除事件
            if (bufferID >= FINGER_CHAR_NUM)
            {
                // 合并特征
                FINGER_LOG("Finger_GenChar_cb PS_REG_MODEL\r\n");
                Finger_send_cmd_pack(PS_REG_MODEL, NULL, 0);
            }
            else
            {
                // 合成特征次数太少，上报失败
                fingerMsg.action = FINGER_ACTION_ADD_ERR;
                fingerMsg.fingerNumber = temp_save_num;
                OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));

                Finger_EndStep();
            }
        }
        add_state = 0;
    }
    else
    {
        if (pPackeData->confrim_code == ACK_SUCCESS)
        {
            // 验证指纹
            Finger_Search();
            cur_status = FINGER_BUSY;
            fpt_verify_flag = 1; 
            //FINGER_LOG("fpt_verify_flag 01\r\n");
        }
        else
        {
            fingerMsg.action = FINGER_ACTION_GET_IMAGE_ERR;
            fingerMsg.fingerNumber = temp_save_num;
            OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));

            Finger_EndStep();
        }
    }
}

/**
 * @brief  合并特征回调
 * @note
 * @return
 */
void Finger_RegModel_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    FingerMsg_t fingerMsg;

    FINGER_LOG("Finger_RegModel_cb pPackeData->confrim_code %x\r\n",pPackeData->confrim_code);

    if (pPackeData->confrim_code == ACK_SUCCESS) // 成功
    {
        // 储存模板
        Finger_StoreChar();
    }
    else
    {
        // 上报失败
        fingerMsg.action = FINGER_ACTION_ADD_ERR;
        fingerMsg.fingerNumber = temp_save_num;
        OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));

        Finger_EndStep();
    }
}

/**
 * @brief  储存模板
 * @note
 * @return
 */
void Finger_StoreChar_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    FingerMsg_t fingerMsg;

    FINGER_LOG("Finger_StoreChar_cb pPackeData->confrim_code %x\r\n",pPackeData->confrim_code);

    if (pPackeData->confrim_code == ACK_SUCCESS) // 成功
    {
        // 上报成功
        fingerMsg.action = FINGER_ACTION_ADD_OK;
    }
    else
    {
        // 上报失败
        fingerMsg.action = FINGER_ACTION_ADD_ERR;
    }

    fingerMsg.fingerNumber = temp_save_num;
    OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));
    OSAL_EventSingleCreate(COMP_FINGER, EVENT_FINGER_LED_OFF, 500, EVT_PRIORITY_MEDIUM);
}

/**
 * @brief  搜索指纹回调
 * @note
 * @return
 */
void PS_Search_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    FingerMsg_t fingerMsg;
    uint16_t num;

    FINGER_LOG(" PS_Search_cb verify: %02X\r\n", pPackeData->confrim_code);

    if (pPackeData->confrim_code == ACK_SUCCESS)
    {
        // 搜索到指纹
        memcpy(&num, pPackeData->dataBuf, 2);
        num=OSAL_SWAP16(num);
        fingerMsg.action = FINGER_ACTION_VERIFY_OK;
        fingerMsg.fingerNumber = num;
        FINGER_LOG("FINGER_ACTION_VERIFY_OK num=%d \r\n", fingerMsg.fingerNumber);
        OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));
        
    }
    else
    {
        FINGER_LOG("FINGER_ACTION_VERIFY_ERR\r\n");
        fingerMsg.action = FINGER_ACTION_VERIFY_ERR;
        fingerMsg.fingerNumber = 0xff;
        OSAL_MessagePublish(&fingerMsg, sizeof(fingerMsg));
    }
    OSAL_EventSingleCreate(COMP_FINGER, EVENT_FINGER_LED_OFF, 500, EVT_PRIORITY_MEDIUM);
    Finger_EndStep();
    fpt_verify_flag = 0;
    //FINGER_LOG("fpt_verify_flag 00\r\n");
}

/**
 * @brief  模块握手回调
 * @note
 * @return
 */
void Finger_PsHandShake_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    if (pPackeData->confrim_code == 0)
    {
        FINGER_LOG("Hand Shank ok...\r\n");

        OSAL_SetTaskStatus(TASK_STA_ACTIVE); // 指纹流程开始：禁止系统休眠
        // Finger_AllLedOff();  // 指纹头供电默认蓝色呼吸灯，需要供应商去掉，否则最快速度关闭都会出现灯亮灭
        // 唤醒 握手成功呼吸2s  --- 后续若需要改动让供应商修改所有LED均由我们管控
        OSAL_EventSingleCreate(COMP_FINGER, EVENT_FINGER_LED_OFF, 2000, EVT_PRIORITY_MEDIUM);
        // OSAL_EventSingleCreate(COMP_FINGER, EVENT_FINGER_DETECT, FINGER_PROCESSOR_TIME, EVT_PRIORITY_MEDIUM);
        connect_state = 1;
        //FINGER_LOG("connect_state 002:%x", connect_state);
        Finger_Processor();
        start_flag = 1;
    }
    else
    {
        connect_state = 0;
        //FINGER_LOG("connect_state 003:%x", connect_state);
        start_flag = 0;
        cur_status = FINGER_IDLE;
        //FINGER_LOG("IDLE 001");
        CmdPacketTxInfo.status = TX_STA_IDLE;
        FINGER_LOG("PsHandShaker error code:%2X\r\n", pPackeData->confrim_code);
    }
}

/**
 * @brief  取消指令 回调
 * @note
 * @return
 */
void Finger_PsCancel_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    if (pPackeData->confrim_code == 0) // 取消成功
    {
        FINGER_LOG("Cancel ok\r\n");
    }
}

/**
 * @brief  删除/清空指纹回调
 * @note
 * @return
 */
void Finger_DeleteModel_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    if (pPackeData->confrim_code == 0) // 删除成功
    {
        FINGER_LOG("delete ok\r\n");
    }
    else
    {
        FINGER_LOG("delete fail\r\n");
    }

        // Finger_send_cmd_pack(PS_SLEEP, NULL, 0);
        Finger_DetectNoFinger_cb();

}

/**
 * @brief  读取指纹版本号回调
 * @note
 * @return
 */
void FINGER_ReadVersion_cb(uint8_t *ackpacket)
{
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    if (pPackeData->confrim_code == 0)
    {
        // 版本号存NV
        OSAL_NvWrite(0, pPackeData->dataBuf, (OSAL_SWAP16(pPackeData->head.len)-2));
        FINGER_LOG("ver_len:%d, Version: %s\r\n", (OSAL_SWAP16(pPackeData->head.len)-2), pPackeData->dataBuf);
    }
    else
    {
        FINGER_LOG("Read Version fail\r\n");
    }
    // Finger_send_cmd_pack(PS_SLEEP, NULL, 0);
    // Finger_DetectNoFinger_cb();
}

/**
 * @brief  休眠回调
 * @note
 * @return
 */
void Finger_DetectNoFinger_cb(void)
{
    #if 0
    FINGER_LOG("Finger_DetectNoFinger_cb\r\n");
    #endif
    OSAL_EventDelete(COMP_FINGER, EVENT_FINGER_DETECT); // 删除事件
    OSAL_SetTaskStatus(TASK_STA_NORMAL);                // 指纹流程结束：允许系统休眠
    CmdPacketTxInfo.status = TX_STA_IDLE;
    start_flag = 0;
    cur_status = FINGER_IDLE;
    //FINGER_LOG("IDLE 002");
    // Finger_AllLedOff();
}

/**
 * @brief  休眠回调
 * @note
 * @return
 */
void Finger_PsSleep_cb(uint8_t *ackpacket)
{
    FINGER_LOG("Finger_PsSleep_cb\r\n");
    AckPacket_stu_t *pPackeData = (AckPacket_stu_t *)ackpacket;
    if (pPackeData->confrim_code == 0) // 休眠成功
    {
        FINGER_LOG("sleep ok\r\n");
        Device_Disable(UART_VHW_FINGER);//
        Device_Write(POWER_VHW_FINGER, NULL, 0, 0); // 断电
        OSAL_EventDelete(COMP_FINGER, EVENT_FINGER_DETECT); // 删除事件
        OSAL_SetTaskStatus(TASK_STA_NORMAL); // 指纹流程结束：允许系统休眠
        CmdPacketTxInfo.status = TX_STA_IDLE;
        start_flag = 0;
        cur_status = FINGER_IDLE;
        //FINGER_LOG("IDLE 003");
    }
    else
    {   //TODO: 断电后，再上电，跑初始化，休眠，重试3次?
        FINGER_LOG("sleep fail\r\n");
        Device_Disable(UART_VHW_FINGER);//
        Device_Write(POWER_VHW_FINGER, NULL, 0, 0); // 断电
        OSAL_EventDelete(COMP_FINGER, EVENT_FINGER_DETECT); // 删除事件
        OSAL_SetTaskStatus(TASK_STA_NORMAL); // 指纹流程结束：允许系统休眠
        CmdPacketTxInfo.status = TX_STA_IDLE;
        start_flag = 0;
        cur_status = FINGER_IDLE;
        //FINGER_LOG("IDLE 004");
        //fpt_sleep_flag = 0;//
    }
}

/***************************************中断与邮箱处理********************************************/

// 结束操作
void Finger_EndStep(void)
{
    // 结束前采多一次图判断手指状态
    FINGER_LOG("Finger_EndStep\r\n");
    // CmdPacketTxInfo.status = TX_STA_IDLE;
    // CmdPacketTxInfo.data.cb = NULL;
    Finger_Processor();
}

// 指纹处理函数
void Finger_Processor(void)
{
    #if 0
    FINGER_LOG("Finger_Processor...");
    #endif
    if (finger_status_data.mode == FINGER_WORK_MODE_ADD)
    {
        Finger_send_cmd_pack(PS_GetENROLLIMAGE, NULL, 0);
    }
    else
    {
        Finger_send_cmd_pack(PS_GETIMAGE, NULL, 0);
    }
}

static void Finger_ProcessMbox(uint8_t *msg)
{
    switch (msg[0])
    {
    case FINGER_SETWORKMODE: // 切换指纹任务工作模式
    {
        uint8_t mode;
        mode = msg[1];
        temp_save_num = msg[2];            //
        finger_status_data.enroll_num = 0; // 注册次数清零
        bufferID = 1; //存入缓存次数复位

        if (mode != finger_status_data.mode)
        {
            Finger_Cancel();
            finger_status_data.mode = (WorkMode_enum_t)mode;

            uint8_t uart_on = (uint8_t)Device_Read(POWER_VHW_FINGER, NULL, 0, 0);
            if (uart_on != 1)
            {
                Device_Enable(UART_VHW_FINGER);
                Device_Write(POWER_VHW_FINGER, NULL, 0, 1);
            }
            cur_status = FINGER_BUSY;
            //FINGER_LOG("IDLE 005");
            if (finger_status_data.mode == FINGER_WORK_MODE_ADD)
            {
                FINGER_LOG("switch add mode\r\n");
                OSAL_EventRepeatCreate(COMP_FINGER, EVENT_GETIMAGE_PROTOCOL, 50, EVT_PRIORITY_MEDIUM);
            }
            else if (finger_status_data.mode == FINGER_WORK_MODE_VERIFY)
            {
                FINGER_LOG("switch verify mode\r\n");
                OSAL_EventDelete(COMP_FINGER, EVENT_GETIMAGE_PROTOCOL); // 删除事件
                OSAL_EventSingleCreate(COMP_FINGER, EVENT_GETIMAGE_PROTOCOL, 50, EVT_PRIORITY_MEDIUM);
                
            }
            else if (finger_status_data.mode == FINGER_WORK_MODE_DISABLE)
            {
                FINGER_LOG("switch disable mode\r\n");
                OSAL_EventSingleCreate(COMP_FINGER, EVENT_GETIMAGE_PROTOCOL, 50, EVT_PRIORITY_MEDIUM);
            }
        }
    }
    break;
    case FINGER_DELETEIMAGE: // 删除指纹图像
    {
        uint8_t startNum, endNum, delNum;
        startNum = msg[1];
        endNum = msg[2];
        FINGER_LOG("Users_DeleteFinger: startNum = 0x%02x, endNum = 0x%02x\r\n", startNum, endNum);
        // if (endNum >= startNum)
        {
            delNum = endNum;
            if (startNum == 0XFF && endNum == 0XFF) // 删除全部
            {
                Finger_send_cmd_pack(PS_EMPTY, NULL, 0);
            }
            else
            {
                Finger_DeleteChar(startNum, delNum);
            }
        }
    }
    break;
    case UART_FINGER_LED_CONTROL:
    {
        Finger_Led_Control_stu_t ledControl = {0};
        memset(&ledControl, 0 , sizeof(Finger_Led_Control_stu_t));
        memcpy(&ledControl, (Finger_Led_Control_stu_t *)&msg[1], sizeof(Finger_Led_Control_stu_t));
        FINGER_LOG("led control: mode = 0x%02x, led = 0x%02x  times 0x%02x\r\n", ledControl.mode , ledControl.startColor, ledControl.times);
        Finger_LedSet(&ledControl);
    }
    break;
    default:
        break;
    }
}

/**
  * @brief  按钮状态改变
  * @note   检测到端口有动作就会调用该函数
  *         该函数会在中断里面以回调的形式调用
  *         
  * @param  name：端口名称
  * @param  status：端口状态
  * @param  times：连按次数
  */
static void Fingerint_StatusChange(char *name, uint8_t status, uint8_t times)
{
    ButtonMsg_t button;

	/* 按钮动作暂存缓存区 */
	strcpy(button.name, name);
	button.action = status;
	button.times = times;

    if (button.action == USER_ACTION_PRESS)
    {
        if (fpt_sleep_flag == 1)//
        {
            OSAL_UpdateSleepTime(1000, 1);//
            uint8_t uart_on = (uint8_t)Device_Read(POWER_VHW_FINGER, NULL, 0, 0);
            if (uart_on != 1)
            {
                Device_Enable(UART_VHW_FINGER);
                Device_Write(POWER_VHW_FINGER, NULL, 0, 1);
                FINGER_LOG("Fingerint 1\r\n");
                OSAL_EventSingleCreate(COMP_FINGER, EVENT_SHAKE_PROTOCOL, 100, EVT_PRIORITY_MEDIUM);
                fpt_sleep_flag = 0;
            }
            // FINGER_LOG("Fingerint 1\r\n");
            // OSAL_EventSingleCreate(COMP_FINGER, EVENT_SHAKE_PROTOCOL, 100, EVT_PRIORITY_MEDIUM);
            // fpt_sleep_flag = 0;
        }
       
    }
    else
    {
        FINGER_LOG("Fingerint 2\r\n");
    }
}

/**
  * @brief  指纹中断引脚初始化
  *         
  * @note   定义指纹中断引脚端口数据，并初始化端口
  */
static void Finger_int_Init(void)
{
    InputPort_stu_t button_list[] = {
        {"FINGER_INT", IRQ_VHW_FINGER, INPUT_PORT_LOGIC_HIGH, INPUT_PORT_FUNC_MULTI},  //指纹中断引脚
    };
    /* 注册端口 */
    InputPort_Registered(button_list, OSAL_LENGTH(button_list), Fingerint_StatusChange);
    InputPort_EnableProt("FINGER_INT");
}

/**
 * @brief  指纹组件初始化
 * @note
 * @return
 */
static void Finger_Init()
{
    FINGER_LOG("Finger_Init\r\n");
    if (init_flag == 0)
    {
        /* 创建RX环形缓存 */
        CmdPacketRxInfo.rbHandle = OSAL_RingBufferCreate(FINGER_RB_RXBUF_LENGTH, 1);
        /* 创建TX环形缓存 */
        CmdPacketTxInfo.tbHandle = OSAL_RingBufferCreate(5, sizeof(uart_txcmd_packet_stu_t));
        /* 注册串口接收回调 */
        Device_RegisteredCB(UART_VHW_FINGER, Finger_Receivecb);
        /* 初始化UART协议层 */
        Finger_ProtocolInit();

        Device_ConfigCB(IRQ_VHW_FINGER, ENABLE);
        init_flag = 1;

        //OSAL_EventSingleCreate(COMP_FINGER, EVENT_FINGER_VERSION, 50, EVT_PRIORITY_MEDIUM);
        Finger_int_Init();
    }
}

// FINGER任务函数
static uint32_t Finger_Task(uint32_t event)
{
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)
    {
        FINGER_LOG("Finger_Task start\r\n");
        // Device_Enable(UART_VHW_FINGER);
        Finger_Init();

        Device_Enable(UART_VHW_FINGER);
        Device_Write(POWER_VHW_FINGER, NULL, 0, 1);
        OSAL_EventSingleCreate(COMP_FINGER, EVENT_SHAKE_PROTOCOL, 100, EVT_PRIORITY_MEDIUM);
        OSAL_EventRepeatCreate(COMP_FINGER, EVENT_UART_PROTOCOL, 10, EVT_PRIORITY_MEDIUM);

        return (event ^ EVENT_SYS_START);
    }

    /* 串口处理发送TX事件 */
    if (event & EVENT_UART_PROTOCOL)
    {
        //uint8_t irq_flag = (uint8_t)Device_Read(IRQ_VHW_FINGER, NULL, 0, 0);
        static uint8_t count = 0;
        count++;
        if (count >= 20)//
        {
            count = 0;
            //if (irq_flag == 1 && cur_status == FINGER_IDLE)
            if (cur_status == FINGER_IDLE)
            {
                //uint8_t uart_on = (uint8_t)Device_Read(POWER_VHW_FINGER, NULL, 0, 0);
                // if (uart_on != 1)
                // {
                //     Device_Enable(UART_VHW_FINGER);
                //     Device_Write(POWER_VHW_FINGER, NULL, 0, 1);
                //     OSAL_EventSingleCreate(COMP_FINGER, EVENT_SHAKE_PROTOCOL, 50, EVT_PRIORITY_MEDIUM);
                // }
                //else
                //{
                    if(fpt_verify_flag == 1) 
                    {
                        FINGER_LOG("EVENT_UART_PROTOCOL fpt_verify_flag = 1");                      
                    }
                    else
                    {
                        if (connect_state == 1 && fpt_sleep_flag == 0) //发了休眠指令， 在休眠前按了指纹，休眠后就无法按指纹？--按了指纹，就再发一下休眠指令
                        {
                           Finger_Processor();//00D 
                        }
                    }       
                //}

                cur_status = FINGER_BUSY;
                return (event ^ EVENT_UART_PROTOCOL);
            }
        }

        Finger_ProtocolPro();
        Finger_ProcessTxQueue();
        return (event ^ EVENT_UART_PROTOCOL);
    }

    /* 指纹处理事件 */
    if (event & EVENT_FINGER_DETECT)
    {
        FINGER_LOG("EVENT_FINGER_DETECT\r\n");
        Finger_Processor();
        return (event ^ EVENT_FINGER_DETECT);
    }

    /* 指纹握手事件 */
    if (event & EVENT_SHAKE_PROTOCOL)
    {
        FINGER_LOG("EVENT_SHAKE_PROTOCOL\r\n");
        Finger_send_cmd_pack(PS_HAND_SHAKE, NULL, 0);
        return (event ^ EVENT_SHAKE_PROTOCOL);
    }

    /* 添加指纹采图事件 */
    if (event & EVENT_GETIMAGE_PROTOCOL)
    {
        FINGER_LOG("add_state:%d, TxInfo:%d\r\n", add_state, CmdPacketTxInfo.status);
        if (add_state == 0 && CmdPacketTxInfo.status == TX_STA_IDLE)
        {
            Finger_send_cmd_pack(PS_GetENROLLIMAGE, NULL, 0);
        }
        return (event ^ EVENT_GETIMAGE_PROTOCOL);
    }

    /* 指纹读取版本号事件 */
    // if (event & EVENT_FINGER_VERSION)
    // {
    //     FINGER_LOG("EVENT_FINGER_VERSION\r\n");
    //     Finger_ReadVersion();
    //     return (event ^ EVENT_FINGER_VERSION);
    // }
        /* 指纹读取版本号事件 */
    if (event & EVENT_FINGER_LED_OFF)
    {
        FINGER_LOG("EVENT_FINGER_LED_OFF\r\n");
        Finger_AllLedOff();
        return (event ^ EVENT_FINGER_LED_OFF);
    }

    /* 邮箱处理事件 */
    if (event & EVENT_SYS_MBOX)
    {
        uint8_t buffer[50] = {0};
        while (OSAL_MboxAccept(buffer))
        {
            Finger_ProcessMbox(buffer);
        }
        return (event ^ EVENT_SYS_MBOX);
    }

    /* 系统休眠事件 */
    if (event & EVENT_SYS_SLEEP)
    {
        CmdPacketTxInfo.status = TX_STA_IDLE;
        start_flag = 0;
        connect_state = 0;
        Device_Disable(UART_VHW_FINGER);
        Device_Write(POWER_VHW_FINGER, NULL, 0, 0);
        fpt_sleep_flag = 0;
        fpt_verify_flag = 0;
        FINGER_LOG("Finger task sleep\r\n");
        return (event ^ EVENT_SYS_SLEEP);
    }
    return 0;
}

COMPONENT_TASK_EXPORT(COMP_FINGER, Finger_Task, FINGER_NV_SIZE);

/**
 * @brief  指纹唤醒逻辑处理
 * @param
 * @return
 */
static int32_t Finger_WakeHandle(uint32_t dev)
{
    if (1)//(Device_Write(POWER_VHW_FINGER, NULL, 0, 1) == 1)
    {
        return 1;
    }
    else
    {
        return -1;
    }
}
COMPONENT_WAKEUP_EXPORT(COMP_FINGER, Finger_WakeHandle, IRQ_VHW_FINGER);

